#include "xict_cpp/core/stage/draw_trajectory_processor.h"

namespace xict_cpp {
    namespace core {
        namespace stage {
            bool DrawTrajectoryStage::Init() {
                std::vector<DrawTrajectoryStageParams> params;
                return Init(params);
            }

            bool DrawTrajectoryStage::Init(
                const std::vector<DrawTrajectoryStageParams>& params) {
                params_lists_ = params;
                return Initialize();
            }

            bool DrawTrajectoryStage::Initialize() {
                color_step_ = 1.0 / params_lists_[0].multi_colors.size();
                pubs_.resize(params_lists_.size());
                for (int i = 0; i < params_lists_.size(); i++) {
                    if (params_lists_[i].enable_pub) {
                        pubs_[i] =
                            eCAL::protobuf::CPublisher<xcmg_proto::OpencvImage>(
                                params_lists_[i].pub_topic);
                    }
                }

#ifdef GRADER
                sub_.rotation_angle_sub = std::make_shared<
                    eCAL::protobuf::CSubscriber<xcmg_proto::Grader_CAN>>(
                    params_lists_[0].vehicle_type);
                auto lambda = [&](const char*,
                                  const xcmg_proto::Grader_CAN& data, long long,
                                  long long, long long) {
                    CallbackRotationAngle(params_lists_[0].vehicle_type.c_str(),
                                          data, 0, 0, 0);
                };
#endif

#ifdef LOADER
                sub_.rotation_angle_sub = std::make_shared<
                    eCAL::protobuf::CSubscriber<xcmg_proto::Loader_CAN>>(
                    params_lists_[0].vehicle_type);
                auto lambda = [&](const char*,
                                  const xcmg_proto::Grader_CAN& data, long long,
                                  long long, long long) {
                    CallbackRotationAngle(params_lists_[0].vehicle_type.c_str(),
                                          data, 0, 0, 0);
                };
#endif

#ifdef BACKHOE_LOADER
                sub_.rotation_angle_sub = std::make_shared<
                    eCAL::protobuf::CSubscriber<xcmg_proto::BackhoeLoader_CAN>>(
                    params_lists_[0].vehicle_type);
                auto lambda = [&](const char*,
                                  const xcmg_proto::BackhoeLoader_CAN& data,
                                  long long, long long, long long) {
                    CallbackRotationAngle(params_lists_[0].vehicle_type.c_str(),
                                          data, 0, 0, 0);
                };
#endif

#ifdef SCRAPER
                sub_.rotation_angle_sub = std::make_shared<
                    eCAL::protobuf::CSubscriber<xcmg_proto::Scraper_CAN>>(
                    params_lists_[0].vehicle_type);
                auto lambda = [&](const char*,
                                  const xcmg_proto::Scraper_CAN& data,
                                  long long, long long, long long) {
                    CallbackRotationAngle(params_lists_[0].vehicle_type.c_str(),
                                          data, 0, 0, 0);
                };
#endif
                sub_.rotation_angle_sub->AddReceiveCallback(lambda);

                return true;
            }

            void DrawTrajectoryStage::Reset() { }

            cv::Mat DrawTrajectoryStage::DrawTrajectoryWithSingleGlowArrow(
                const DrawTrajectoryStageParams& params,
                const std::vector<std::vector<cv::Point3d>>&
                    trajectory_points_list,
                double time) {
                // 创建一个单独的覆盖层用于抗锯齿绘制
                cv::Mat overlay = cv::Mat::zeros(
                    params.image_height, params.image_width, params.image_type);

                // 遍历每一组轨迹点
                for (size_t idx = 0; idx < trajectory_points_list.size();
                     ++idx) {
                    const std::vector<cv::Point3d>& trajectory_points =
                        trajectory_points_list[idx];

                    // 用于存储投影后的2D图像点
                    std::vector<cv::Point2d> image_points;
                    // 将3D点投影到图像平面上
                    cv::projectPoints(trajectory_points, params.rotation_vector,
                                      params.translation_vector,
                                      params.camera_matrix, params.dist_coeffs,
                                      image_points);

                    // 根据时间计算流场偏移（法线方向）
                    double flow_offset = std::fmod(time * 0.5, 1.0);

                    // 并行绘制轨迹线
                    cv::parallel_for_(
                        cv::Range(1, params.num_points),
                        [&](const cv::Range& range) {
                            for (int i = range.start; i < range.end; ++i) {
                                // 绘制主线条
                                cv::line(overlay, image_points[i - 1],
                                         image_points[i],
                                         cv::Scalar(params.line_color[0],
                                                    params.line_color[1],
                                                    params.line_color[2]),
                                         params.line_thickness, cv::LINE_AA);

                                // 绘制发光效果
                                for (int g = 1; g <= params.glow_line_width;
                                     ++g) {
                                    cv::Scalar glow =
                                        cv::Scalar(params.line_color[0],
                                                   params.line_color[1],
                                                   params.line_color[2]) *
                                        (1.0 - g * params.glow_line_ratio);
                                    cv::line(overlay, image_points[i - 1],
                                             image_points[i], glow,
                                             params.line_thickness +
                                                 g * params.glow_line_thickness,
                                             cv::LINE_AA);
                                }

                                // Add distance markers
                                if (i == params.position_5m ||
                                    i == params.position_10m ||
                                    i == params.position_15m) {
                                    std::string text;
                                    if (i == params.position_5m) {
                                        text = "5m";
                                    } else if (i == params.position_10m) {
                                        text = "10m";
                                    } else if (i == params.position_15m) {
                                        text = "15m";
                                    }
                                    cv::Point textPos = image_points[i];

                                    // Adjust text position above the line
                                    textPos.x += params.text_position_x;
                                    textPos.y -= params.text_position_y;
                                    // Use a mutex to ensure thread-safe drawing
                                    // of text
                                    static std::mutex mtx;
                                    std::lock_guard<std::mutex> lock(mtx);

                                    // Draw text with glow effect
                                    for (int g = params.glow_font_width; g >= 0;
                                         --g) {
                                        cv::Scalar text_color =
                                            (g == 0)
                                                ? cv::Scalar(
                                                      params
                                                          .font_color_inner[0],
                                                      params
                                                          .font_color_inner[1],
                                                      params
                                                          .font_color_inner[2])
                                                : cv::Scalar(
                                                      params
                                                          .font_color_outer[0],
                                                      params
                                                          .font_color_outer[1],
                                                      params
                                                          .font_color_outer[2]);
                                        cv::putText(overlay, text, textPos,
                                                    cv::FONT_HERSHEY_SIMPLEX,
                                                    params.font_size,
                                                    text_color,
                                                    params.font_thickness + g,
                                                    cv::LINE_AA);
                                    }
                                }
                            }
                        });

                    // 绘制流动的箭头
                    int arrow_index =
                        static_cast<int>(flow_offset * (params.num_points - 1));
                    if (arrow_index < params.num_points - 1) {
                        cv::Point2d base = image_points[arrow_index];
                        cv::Point2d tip  = image_points[arrow_index + 1];
                        double angle = atan2(tip.y - base.y, tip.x - base.x);

                        cv::Point2d arrowP1(
                            base.x - params.arrow_length *
                                         cos(angle + params.arrow_angle),
                            base.y - params.arrow_length *
                                         sin(angle + params.arrow_angle));
                        cv::Point2d arrowP2(
                            base.x - params.arrow_length *
                                         cos(angle - params.arrow_angle),
                            base.y - params.arrow_length *
                                         sin(angle - params.arrow_angle));

                        // 绘制箭头
                        cv::line(overlay, base, arrowP1,
                                 cv::Scalar(params.arrow_color[0],
                                            params.arrow_color[1],
                                            params.arrow_color[2]),
                                 params.arrow_thickness, cv::LINE_AA);
                        cv::line(overlay, base, arrowP2,
                                 cv::Scalar(params.arrow_color[0],
                                            params.arrow_color[1],
                                            params.arrow_color[2]),
                                 params.arrow_thickness, cv::LINE_AA);

                        // 为箭头添加发光效果
                        for (int g = 1; g <= params.glow_arrow_width; ++g) {
                            cv::Scalar glowArrow =
                                cv::Scalar(params.arrow_color[0],
                                           params.arrow_color[1],
                                           params.arrow_color[2]) *
                                (1.0 - g * params.glow_arrow_ratio);
                            cv::line(overlay, base, arrowP1, glowArrow,
                                     params.arrow_thickness +
                                         g * params.glow_arrow_thickness,
                                     cv::LINE_AA);
                            cv::line(overlay, base, arrowP2, glowArrow,
                                     params.arrow_thickness +
                                         g * params.glow_arrow_thickness,
                                     cv::LINE_AA);
                        }
                    }
                }
                return overlay;
            }

            cv::Mat DrawTrajectoryStage::DrawTrajectoryWithMultipleGlowArrows(
                const DrawTrajectoryStageParams& params,
                const std::vector<std::vector<cv::Point3d>>&
                    trajectory_points_list,
                double time) {
                // 创建一个单独的覆盖层用于抗锯齿绘制
                cv::Mat overlay = cv::Mat::zeros(
                    params.image_height, params.image_width, params.image_type);

                // 遍历每一组轨迹点
                for (size_t idx = 0; idx < trajectory_points_list.size();
                     ++idx) {
                    const std::vector<cv::Point3d>& trajectory_points =
                        trajectory_points_list[idx];

                    // 用于存储投影后的2D图像点
                    std::vector<cv::Point2d> image_points;
                    // 将3D点投影到图像平面上
                    cv::projectPoints(trajectory_points, params.rotation_vector,
                                      params.translation_vector,
                                      params.camera_matrix, params.dist_coeffs,
                                      image_points);

                    // 根据时间计算流场偏移
                    double flow_offset =
                        std::fmod(time * params.arrow_speed, 1.0);

                    // 并行绘制轨迹线
                    cv::parallel_for_(
                        cv::Range(1, params.num_points),
                        [&](const cv::Range& range) {
                            for (int i = range.start; i < range.end; ++i) {
                                // 绘制主线条
                                cv::line(overlay, image_points[i - 1],
                                         image_points[i],
                                         cv::Scalar(params.line_color[0],
                                                    params.line_color[1],
                                                    params.line_color[2]),
                                         params.line_thickness, cv::LINE_AA);

                                // 绘制发光效果
                                for (int g = 1; g <= params.glow_line_width;
                                     ++g) {
                                    cv::Scalar glow =
                                        cv::Scalar(params.line_color[0],
                                                   params.line_color[1],
                                                   params.line_color[2]) *
                                        (1.0 - g * params.glow_line_ratio);
                                    cv::line(overlay, image_points[i - 1],
                                             image_points[i], glow,
                                             params.line_thickness +
                                                 g * params.glow_line_thickness,
                                             cv::LINE_AA);
                                }

                                // Add distance markers
                                if (i == params.position_5m ||
                                    i == params.position_10m ||
                                    i == params.position_15m) {
                                    std::string text;
                                    if (i == params.position_5m) {
                                        text = "5m";
                                    } else if (i == params.position_10m) {
                                        text = "10m";
                                    } else if (i == params.position_15m) {
                                        text = "15m";
                                    }
                                    cv::Point textPos = image_points[i];

                                    // Adjust text position above the line
                                    textPos.x += params.text_position_x;
                                    textPos.y -= params.text_position_y;

                                    // Use a mutex to ensure thread-safe drawing
                                    // of text
                                    static std::mutex mtx;
                                    std::lock_guard<std::mutex> lock(mtx);

                                    // Draw text with glow effect
                                    for (int g = params.glow_font_width; g >= 0;
                                         --g) {
                                        cv::Scalar text_color =
                                            (g == 0)
                                                ? cv::Scalar(
                                                      params
                                                          .font_color_inner[0],
                                                      params
                                                          .font_color_inner[1],
                                                      params
                                                          .font_color_inner[2])
                                                : cv::Scalar(
                                                      params
                                                          .font_color_outer[0],
                                                      params
                                                          .font_color_outer[1],
                                                      params
                                                          .font_color_outer[2]);
                                        cv::putText(overlay, text, textPos,
                                                    cv::FONT_HERSHEY_SIMPLEX,
                                                    params.font_size,
                                                    text_color,
                                                    params.font_thickness + g,
                                                    cv::LINE_AA);
                                    }
                                }
                            }
                        });

                    // 绘制流动的箭头
                    for (int i = 0; i < params.num_points;
                         i += params.arrow_interval) {
                        int arrow_index =
                            static_cast<int>(
                                (flow_offset +
                                 i / static_cast<double>(params.num_points)) *
                                (params.num_points - 1)) %
                            params.num_points;
                        if (arrow_index < params.num_points - 1) {
                            cv::Point2d base = image_points[arrow_index];
                            cv::Point2d tip  = image_points[arrow_index + 1];
                            double angle =
                                atan2(tip.y - base.y, tip.x - base.x);

                            cv::Point2d arrowP1(
                                base.x - params.arrow_length *
                                             cos(angle + params.arrow_angle),
                                base.y - params.arrow_length *
                                             sin(angle + params.arrow_angle));
                            cv::Point2d arrowP2(
                                base.x - params.arrow_length *
                                             cos(angle - params.arrow_angle),
                                base.y - params.arrow_length *
                                             sin(angle - params.arrow_angle));

                            // 绘制箭头
                            cv::line(overlay, base, tip,
                                     cv::Scalar(params.arrow_color[0],
                                                params.arrow_color[1],
                                                params.arrow_color[2]),
                                     params.arrow_thickness, cv::LINE_AA);
                            cv::line(overlay, base, arrowP1,
                                     cv::Scalar(params.arrow_color[0],
                                                params.arrow_color[1],
                                                params.arrow_color[2]),
                                     params.arrow_thickness, cv::LINE_AA);
                            cv::line(overlay, base, arrowP2,
                                     cv::Scalar(params.arrow_color[0],
                                                params.arrow_color[1],
                                                params.arrow_color[2]),
                                     params.arrow_thickness, cv::LINE_AA);

                            // 为箭头添加发光效果
                            for (int g = 1; g <= params.glow_arrow_width; ++g) {
                                cv::Scalar glowArrow =
                                    cv::Scalar(params.arrow_color[0],
                                               params.arrow_color[1],
                                               params.arrow_color[2]) *
                                    (1.0 - g * params.glow_arrow_ratio);
                                cv::line(overlay, base, arrowP1, glowArrow,
                                         params.arrow_thickness +
                                             g * params.glow_arrow_thickness,
                                         cv::LINE_AA);
                                cv::line(overlay, base, arrowP2, glowArrow,
                                         params.arrow_thickness +
                                             g * params.glow_arrow_thickness,
                                         cv::LINE_AA);
                            }
                        }
                    }
                }

                return overlay;
            }

            cv::Mat DrawTrajectoryStage::DrawTrajectoryWithColorGlow(
                const DrawTrajectoryStageParams& params,
                const std::vector<std::vector<cv::Point3d>>&
                    trajectory_points_list,
                double time) {
                // Create a separate overlay for anti-aliased drawing
                cv::Mat overlay = cv::Mat::zeros(
                    params.image_height, params.image_width, params.image_type);

                // 遍历每一组轨迹点
                for (size_t idx = 0; idx < trajectory_points_list.size();
                     ++idx) {
                    const std::vector<cv::Point3d>& trajectory_points =
                        trajectory_points_list[idx];

                    std::vector<cv::Point2d> image_points;
                    cv::projectPoints(trajectory_points, params.rotation_vector,
                                      params.translation_vector,
                                      params.camera_matrix, params.dist_coeffs,
                                      image_points);

                    // Calculate the flow offset based on time
                    double flow_offset = std::fmod(time * 0.5, 1.0);

                    cv::parallel_for_(
                        cv::Range(1, params.num_points),
                        [&](const cv::Range& range) {
                            for (int i = range.start; i < range.end; ++i) {
                                double base_progress =
                                    static_cast<double>(i) / params.num_points;
                                // Apply the flow offset to create a moving
                                // effect in the opposite direction
                                double progress = std::fmod(
                                    1.0 - base_progress + flow_offset, 1.0);

                                cv::Scalar color;

                                for (int i = 0; i < params.multi_colors.size();
                                     ++i) {
                                    if (progress >= i * color_step_ &&
                                        progress < (i + 1) * color_step_) {
                                        auto it = params.color_maps.find(
                                            params.multi_colors[i]);
                                        if (it != params.color_maps.end()) {
                                            color = it->second;
                                        }
                                        break;
                                    }
                                }

                                // Calculate alpha based on the distance from
                                // the flow offset
                                double alpha =
                                    1.0 -
                                    std::min(std::abs(base_progress -
                                                      (1.0 - progress)),
                                             std::min(base_progress + progress,
                                                      2.0 - base_progress -
                                                          progress));

                                // Apply alpha to the color
                                cv::Scalar glow_color =
                                    color *
                                    std::pow(alpha,
                                             params.multi_color_alpha_ratio);

                                // Draw the main line
                                cv::line(overlay, image_points[i - 1],
                                         image_points[i], glow_color,
                                         params.line_thickness, cv::LINE_AA);

                                // Draw glow effect
                                for (int g = 1; g <= params.glow_line_width;
                                     ++g) {
                                    cv::Scalar glow =
                                        glow_color *
                                        (1.0 - g * params.glow_line_ratio);
                                    cv::line(overlay, image_points[i - 1],
                                             image_points[i], glow,
                                             params.line_thickness +
                                                 g * params.glow_line_thickness,
                                             cv::LINE_AA);
                                }

                                // Add distance markers
                                if (i == params.position_5m ||
                                    i == params.position_10m ||
                                    i == params.position_15m) {
                                    std::string text;
                                    if (i == params.position_5m) {
                                        text = "5m";
                                    } else if (i == params.position_10m) {
                                        text = "10m";
                                    } else if (i == params.position_15m) {
                                        text = "15m";
                                    }
                                    cv::Point textPos = image_points[i];

                                    textPos.x += params.text_position_x;
                                    textPos.y -= params.text_position_y;

                                    // Use a mutex to ensure thread-safe drawing
                                    // of text
                                    static std::mutex mtx;
                                    std::lock_guard<std::mutex> lock(mtx);

                                    // Draw text with glow effect
                                    for (int g = params.glow_font_width; g >= 0;
                                         --g) {
                                        cv::Scalar text_color =
                                            (g == 0)
                                                ? cv::Scalar(
                                                      params
                                                          .font_color_inner[0],
                                                      params
                                                          .font_color_inner[1],
                                                      params
                                                          .font_color_inner[2])
                                                : cv::Scalar(
                                                      params
                                                          .font_color_outer[0],
                                                      params
                                                          .font_color_outer[1],
                                                      params
                                                          .font_color_outer[2]);
                                        cv::putText(overlay, text, textPos,
                                                    cv::FONT_HERSHEY_SIMPLEX,
                                                    params.font_size,
                                                    text_color,
                                                    params.font_thickness + g,
                                                    cv::LINE_AA);
                                    }
                                }
                            }
                        });
                }
                return overlay;
            }

            cv::Mat DrawTrajectoryStage::DrawTrajectoryWithGradientColorGlow(
                const DrawTrajectoryStageParams& params,
                const std::vector<std::vector<cv::Point3d>>&
                    trajectory_points_list,
                double time) {
                // Create a separate overlay for anti-aliased drawing
                cv::Mat overlay = cv::Mat::zeros(
                    params.image_height, params.image_width, params.image_type);

                // 遍历每一组轨迹点
                for (size_t idx = 0; idx < trajectory_points_list.size();
                     ++idx) {
                    const std::vector<cv::Point3d>& trajectory_points =
                        trajectory_points_list[idx];
                    std::vector<cv::Point2d> image_points;
                    cv::projectPoints(trajectory_points, params.rotation_vector,
                                      params.translation_vector,
                                      params.camera_matrix, params.dist_coeffs,
                                      image_points);

                    // Calculate the flow offset based on time
                    double flow_offset = std::fmod(time, 1.0);

                    cv::parallel_for_(
                        cv::Range(1, params.num_points),
                        [&](const cv::Range& range) {
                            for (int i = range.start; i < range.end; ++i) {
                                double base_progress =
                                    static_cast<double>(i) / params.num_points;
                                // Apply the flow offset to create a moving
                                // effect in the opposite direction
                                double progress = std::fmod(
                                    1.0 - base_progress + flow_offset, 1.0);

                                cv::Scalar color;

                                if (progress < 0.625) {
                                    color =
                                        cv::Scalar(255 * (1 - progress * 1.6),
                                                   255 * progress * 1.6, 0);
                                } else if (progress < 1.0) {
                                    double local_progress =
                                        (progress - 0.625) / 0.375;
                                    color = cv::Scalar(
                                        0, 255 * (1 - local_progress),
                                        255 * local_progress);
                                } else {
                                    color = cv::Scalar(0, 0, 255);
                                }

                                // Add alpha channel for transparency
                                color[3] = params.alpha_channel_transparency;

                                double alpha = std::pow(
                                    1.0 - std::min(
                                              std::abs(base_progress -
                                                       (1.0 - progress)),
                                              std::min(base_progress + progress,
                                                       2.0 - base_progress -
                                                           progress)),
                                    0.5);   // Adjust power for smoother
                                            // transition

                                // Apply alpha to the color
                                color *= alpha;

                                cv::line(overlay, image_points[i - 1],
                                         image_points[i], color,
                                         params.line_thickness, cv::LINE_AA);

                                // Add distance markers (only if alpha is high
                                // enough to be visible)
                                if ((i == params.position_5m ||
                                     i == params.position_10m ||
                                     i == params.position_15m) &&
                                    alpha > 0.7) {
                                    std::string text;
                                    if (i == params.position_5m) {
                                        text = "5m";
                                    } else if (i == params.position_10m) {
                                        text = "10m";
                                    } else if (i == params.position_15m) {
                                        text = "15m";
                                    }

                                    cv::Point textPos = image_points[i];
                                    // Adjust text position above the line
                                    textPos.x += params.text_position_x;
                                    textPos.y -= params.text_position_y;

                                    // Use a mutex to ensure thread-safe drawing
                                    // of text
                                    static std::mutex mtx;
                                    std::lock_guard<std::mutex> lock(mtx);

                                    // Draw text
                                    cv::putText(
                                        overlay, text, textPos,
                                        cv::FONT_HERSHEY_SIMPLEX,
                                        params.font_size,
                                        cv::Scalar(params.font_color_outer[0],
                                                   params.font_color_outer[1],
                                                   params.font_color_outer[2],
                                                   255 * alpha),
                                        params.font_thickness, cv::LINE_AA);
                                }
                            }
                        });
                }
                return overlay;
            }

            bool DrawTrajectoryStage::Process() {
                mt_.lock();

                // 遍历每组参数，分别处理每组轨迹
                for (size_t j = 0; j < params_lists_.size(); ++j) {
                    cv::Mat result_img;   // 存储处理后的图像
                    DrawTrajectoryStageParams& params = params_lists_[j];
                    std::vector<std::vector<cv::Point3d>>
                        trajectory_points_list(2);
                    for (int i = 0; i < params.curves_points.size(); i++) {
                        params.curves_points[i].end_point = cv::Point3d(
                            params.line_length * std::sin(angle_of_rotation_) +
                                params.curves_points[i].start_point.x,
                            params.line_length * std::cos(angle_of_rotation_),
                            0);
                        trajectory_points_list[i] =
                            xict_cpp::utils::GenerateBezierCurve(
                                params.curves_points[i].start_point,
                                params.curves_points[i].control_point,
                                params.curves_points[i].end_point);
                    }

                    double time = cv::getTickCount() / cv::getTickFrequency();
                    if (params.trajectory_type == "MULTIGLOWARROWS") {
                        result_img = DrawTrajectoryWithMultipleGlowArrows(
                            params, trajectory_points_list, time);
                    } else if (params.trajectory_type == "SINGLEGLOWARROW") {
                        result_img = DrawTrajectoryWithSingleGlowArrow(
                            params, trajectory_points_list, time);
                    } else if (params.trajectory_type == "COLORGLOW") {
                        result_img = DrawTrajectoryWithColorGlow(
                            params, trajectory_points_list, time);
                    } else if (params.trajectory_type == "GRADIENTCOLORGLOW") {
                        result_img = DrawTrajectoryWithGradientColorGlow(
                            params, trajectory_points_list, time);
                    } else {
                        ADEBUG_F("Error trajectory type");
                    }

                    if (params.enable_pub) {
                        PublishEcalImage(result_img, pubs_[j]);
                    }
                }

                mt_.unlock();
                return true;
            }

            void DrawTrajectoryStage::PublishEcalImage(
                const cv::Mat& img,
                eCAL::protobuf::CPublisher<xcmg_proto::OpencvImage>& pub) {
                xcmg_proto::OpencvImage data;
                data.set_mat_data((char*)img.data,
                                  img.cols * img.rows * img.elemSize());
                data.set_rows(img.rows);
                data.set_cols(img.cols);
                data.set_elt_type(img.type());
                pub.Send(data);
            }
        }   // namespace stage
    }       // namespace core
}   // namespace xict_cpp
